/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						       creature_stack.h

	$Header: /game/creature_stack.h $

	$NoKeywords: $

 ************************************************************************/

#ifndef CREATURE_STACK_H_INCLUDED
#define CREATURE_STACK_H_INCLUDED

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000


// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#pragma warning( disable: 4786 )

#include "abstract_creature.h"
#include "artifact.h"
#include "bitmap_layer_ptr.h"
#include "combat_actor_model_cache.h"
#include "creature_stack_ptr.h"
#include "qualified_adv_object_type.h"
#include "spell_set.h"
#include "sound_cache.h"

enum  t_adv_actor_action_id;
class t_adventure_map;
class t_creature;
class t_creature_array;
enum  t_creature_ability;
enum  t_creature_type;
class t_hero;
class t_material_array;
enum  t_missile_type;
class t_player;
enum  t_skill_mastery;
enum  t_spell;
class t_town;
enum  t_town_type;

int const k_boat_movement = 1500;
int const k_lighthouse_bonus = 1000;

enum t_stat_type
{
	k_stat_luck,
	k_stat_morale,
	k_stat_attack,
	k_stat_unused,
	k_stat_defense,
	k_stat_movement,
	k_stat_speed,
	k_stat_spell_points,

	k_stat_mastery_grass,
	k_stat_mastery_rough,
	k_stat_mastery_swamp,
	k_stat_mastery_lava,
	k_stat_mastery_snow,
	k_stat_mastery_sand,
	k_stat_mastery_dirt,
	k_stat_mastery_subterranean,

	k_stat_count,
	k_stat_type_count = k_stat_count,
};

t_terrain_type  get_terrain_type( t_stat_type stat_type );
t_stat_type		get_stat_type( t_terrain_type terrain );

struct t_temporary_bonus
{
	t_stat_type					stat;
	int							amount;
	t_qualified_adv_object_type object_type;
};

struct t_timed_bonus : public t_temporary_bonus
{
	int days_left;
};

// -----------------------------------------------------------------------
// base class for creature stacks.  Base object is always empty.
// -----------------------------------------------------------------------
class t_creature_stack : public t_counted_object, public t_abstract_creature
{
public:
	typedef std::vector<t_temporary_bonus>	t_bonus_array;
	typedef t_creature_stack_ptr			t_clone_ptr;
	typedef t_combat_actor_model_ptr		t_model_ptr;

	t_creature_stack();
	virtual ~t_creature_stack();

	virtual bool				add( t_artifact const& artifact, bool equip = true );
	virtual bool				add_to_backpack( t_artifact const& artifact, int slot = 32000 );
	void                        add_bonus( t_stat_type stat, int amount ); // permanent bonuses
	void						add_bonus( t_stat_type stat, int amount,   // temporary bonuses
		                                   t_qualified_adv_object_type const& type );
	void						add_temp_bonus( t_stat_type stat, int amount );  // temporary bonus with type of k_adv_object_nothing
	bool						add_timed_bonus( t_stat_type stat, int amount,
												 t_qualified_adv_object_type const& type,
												 int days );
	virtual float				ai_value() const;
	virtual float				ai_value( t_creature_array const* army ) const;
	virtual float 				ai_get_average_defense() const;
	virtual int					ai_get_total_defense() const;
	virtual int					ai_get_total_offense( bool ranged ) const;
	virtual int					ai_get_total_offense() const;
	virtual int					ai_get_total_defense( bool ranged ) const;
	virtual void				ai_start_turn() {}
	virtual bool                can_add( t_creature_type creature ) const;
	virtual bool				can_add( t_creature_stack const& arg ) const;
	virtual bool				can_cast( t_spell spell ) const;
	void						change_raw_adventure_movement( float arg );
	void						clear_temporary_bonuses();
	virtual t_clone_ptr			clone() const;
	virtual int                 compute_scouting_range() const;
	void						copy_bonuses( t_creature_stack const& source );
	float						get_adventure_movement_modifier( float	army_move_bonus,
																 float	army_move_multiplier,
																 float	fastest_raw_move ) const;
	virtual t_town_type         get_alignment() const;
	virtual t_skill_mastery		get_anti_stealth_level() const;
	virtual int					get_army_move_bonus( bool sea_move ) const;
	virtual int					get_army_move_cost( t_terrain_type terrain ) const;
	virtual float				get_army_move_multiplier( bool sea_move ) const;
	virtual std::string			get_army_name() const;
	virtual t_artifact const&	get_artifact( t_artifact_slot slot ) const;
	virtual int				    get_backpack_count() const;
	virtual t_artifact const&   get_backpack_slot( int slot ) const;
	int							get_bonus( t_stat_type stat ) const;
	t_bonus_array const&		get_bonus_array() const;
	int							get_bonus_time( t_qualified_adv_object_type const& type ) const;
	virtual t_model_ptr			get_combat_model( double scale ) const;
	virtual int					get_combat_movement() const;
	virtual t_creature const*	get_const_creature() const;
	virtual t_hero const*		get_const_hero() const;
	t_creature*					get_creature();
	t_creature const*           get_creature() const;
	virtual t_creature_type     get_creature_type() const;
	virtual int					get_damage_high() const;
	virtual int					get_damage_low() const;
	virtual float				get_defense( bool ranged, t_creature_array const& army ) const;
	virtual float				get_defense_basic( bool ranged ) const;
	virtual float				get_defense_bonus( bool ranged ) const;
	virtual	float				get_defense_reduction( bool ranged ) const;
	virtual int                 get_experience_value( int number = -1 ) const;
	virtual int					get_hit_points() const;
    virtual void				get_income( int day, t_material_array& income ) const;
	virtual int					get_leadership_luck_bonus() const;
	virtual int					get_leadership_morale_bonus() const;
	virtual int                 get_luck() const;
	int							get_luck( t_creature_array const& army ) const;
	virtual int					get_magic_resistance( t_player const* owner, t_spell spell ) const;
	virtual int					get_morale() const;
	virtual int                 get_morale( t_creature_array const& army ) const;
	virtual int					get_move_cost( t_terrain_type terrain ) const;
	virtual std::string			get_name( bool include_article = false, int number = -1 ) const;
	virtual int					get_number() const;
	virtual float				get_offense( bool ranged ) const;
	virtual float				get_offense( bool range, t_creature_array const& army ) const;
	virtual t_bitmap_layer_ptr	get_portrait( int height = 52, bool force_awake_portrait = false ) const;
	int							get_raw_adventure_movement() const;
	float						get_raw_adventure_movement_left() const;
	virtual std::string			get_right_click_text() const;
	virtual int					get_shots() const;
	virtual t_skill_mastery		get_skill( t_skill_type skill ) const;
	virtual int					get_speed() const;
	virtual int					get_speed( t_creature_array const& army ) const;
	virtual int                 get_spell_cost( t_spell spell ) const;
	virtual int                 get_spell_power( t_spell spell, t_abstract_grail_data_source const & grail_data, int number = -1 ) const;
	virtual t_skill_mastery		get_stealth_level() const;
	virtual int			        get_maximum_spell_points() const;
	virtual t_missile_type      get_missile_type() const;
	virtual int					get_spell_points() const;
	virtual int					get_stoning_chance() const;
	virtual t_sound_ptr			get_sound( t_adv_actor_action_id action );
	virtual int					get_tactics_defense_bonus( bool sea_battle ) const;
	virtual int					get_tactics_move_bonus( bool sea_battle ) const;
	virtual int					get_tactics_offense_bonus( bool sea_battle ) const;
	virtual int				    get_tactics_speed_bonus( bool sea_battle ) const;
	virtual int					get_wounds() const;
	virtual bool                has_ability( t_creature_ability ability ) const;
	bool                        has_temporary_bonus( t_qualified_adv_object_type const& type ) const;
	bool                        has_timed_bonus( t_qualified_adv_object_type const& type ) const;
	virtual bool				is_active() const;
	virtual bool				is_dead() const;
	virtual	bool				is_undead() const;
	virtual bool				is_spell_active( t_spell spell ) const;
	virtual bool                knows_spell( t_spell spell ) const;
	virtual void                learn_spells( t_town const* town );
	virtual void				on_begin_turn( t_player* owner, t_creature_array* army );
	virtual void				on_end_turn( t_player* owner, t_creature_array* army );
	virtual bool                preplacement( t_adventure_map& map, int pass, t_player* owner );
	virtual void				process_new_day( t_player* owner, bool grow,
												 t_creature_array* army, int day );
	virtual bool                read( std::streambuf& stream );
	virtual bool                read_from_map( std::streambuf& stream );
	virtual void				read_postplacement( t_adventure_map& map );
	virtual void				redistribute_artifacts( t_creature_array & army, t_artifact_list & leftovers );
	virtual void                remove( int amount );
	virtual t_artifact			remove_backpack( int slot );
	void                        set_raw_adventure_movement( float arg );
	virtual bool				set_spell( t_spell spell, bool active = true );
	virtual bool                write( std::streambuf& stream ) const;

protected:
	virtual int	get_luck_bonus( t_hero const& hero ) const;
	virtual int get_morale_bonus( t_hero const& hero ) const;

	typedef std::vector<t_timed_bonus> t_timed_bonus_array;

	int					m_bonus[k_stat_count];
	t_bonus_array		m_bonus_array;
	t_timed_bonus_array	m_timed_bonus_array;

private:
	float				m_raw_adventure_movement;
};


inline void t_creature_stack::add_bonus( t_stat_type stat, int amount )
{
	m_bonus[stat] += amount;
}

inline void t_creature_stack::change_raw_adventure_movement( float arg )
{
	m_raw_adventure_movement += arg;
	if (m_raw_adventure_movement < 0.0)
		m_raw_adventure_movement = 0.0;
}

inline float t_creature_stack::get_raw_adventure_movement_left() const
{
	return m_raw_adventure_movement;
}


inline t_creature const* t_creature_stack::get_creature() const
{
	return get_const_creature();
}

inline t_creature* t_creature_stack::get_creature() 
{
	return const_cast<t_creature*>( get_const_creature() );
}

inline void t_creature_stack::set_raw_adventure_movement( float arg )
{
	m_raw_adventure_movement = arg;
}

// -----------------------------------------------------------------------
// any non-empty stack has a backpack
// -----------------------------------------------------------------------
class t_stack_with_backpack : public t_creature_stack
{
public:
	virtual bool				add( t_artifact const& artifact, bool equip = true );
	virtual bool				add_to_backpack( t_artifact const& artifact, int slot = 32000 );
	virtual int					get_army_move_cost( t_terrain_type terrain ) const;
	virtual int					get_backpack_count() const;
	virtual t_artifact const&	get_backpack_slot( int slot ) const;
	virtual bool				is_spell_active( t_spell spell ) const;
	virtual void				on_begin_turn( t_player* owner, t_creature_array* army );
	virtual void				on_end_turn( t_player* owner, t_creature_array* army );
	virtual void				redistribute_artifacts( t_creature_array & army, t_artifact_list & leftovers );
	virtual t_artifact			remove_backpack( int slot );
	virtual bool				read_from_map( std::streambuf& stream ) = 0;
	virtual bool				set_spell( t_spell spell, bool active = true );

protected:
	bool has_terrain_mastery( t_terrain_type terrain ) const;
	bool read_header( std::streambuf& stream, int& version );
	bool write_header( std::streambuf& stream ) const;

	t_artifact_list m_backpack;
	t_spell_set		m_active_spells;
};


inline int t_stack_with_backpack::get_backpack_count() const
{
	return m_backpack.size();
}

inline t_artifact const& t_stack_with_backpack::get_backpack_slot( int slot ) const
{
	return m_backpack[slot];
}

int get_terrain_cost( t_terrain_type terrain );

#endif // CREATURE_STACK_H_INCLUDED
